﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Vms.Web.Models;
using Vms.Web.Lib;
using System.Data;
using System.Web.Hosting;
using System.Diagnostics;
using System.Runtime.CompilerServices;

namespace Vms.Web.Services
{
    /// <summary>
    /// Control Board Services
    /// Create date: 13/03/2013
    /// Author: Hai Phan Van
    /// Singleton Pattern
    /// </summary>
    public static class BoardServices
    {
        private static bool isSendBusy = false;

        #region TURN_ON_OFF_SCREEN

        /// <summary>
        /// Turn On Screen
        /// </summary>
        /// <param name="screenId"></param>
        /// <param name="isCOMMode">Default Enthenet Mode</param>
        ///[MethodImpl(MethodImplOptions.Synchronized)]
        public static void TurnOnScreen(int screenId, bool isOn = true)
        {
            
            if (isSendBusy == false)
            {
                isSendBusy = true;
                BXIV.InitDLLResource(Process.GetCurrentProcess().Handle);
                isSendBusy = false;
            }
            VmsWebContext vms = new VmsWebContext();
            SCREEN screen = vms.SCREENS.Single(s => s.Id == screenId);
            AddScreenParameters(1, screen);
            int turn = (isOn) ? BXIV.SEND_CMD_POWERON : BXIV.SEND_CMD_POWEROFF;
            if (isSendBusy == false)
            {
                isSendBusy = true;
                int result = BXIV.SendScreenInfo(1, BXIV.SEND_MODE_NET, turn, 0);
                isSendBusy = false;
            }
            BXIV.FreeDLLResource();
            vms.Dispose();
        }

        #endregion

        #region ADD_SCREENS

        /// <summary>
        /// Add Screen Parameters
        /// </summary>
        /// <param name="screenId"></param>
        private static void AddScreenParameters(int screenOrd, SCREEN screen)
        {
            if (isSendBusy == false)
            {
                isSendBusy = true;
                int result = BXIV.AddScreen((int)screen.ControlType, screenOrd, (int)screen.Width, (int)screen.Height,
                    BXIV.SCREEN_TYPE_RGBCOLOR, BXIV.PIXCEL_MODE_GR, BXIV.DATA_DA_POSITYPE, BXIV.DATA_OE_LOW,
                    BXIV.ROW_ORDER_NORMAL, BXIV.SCAN_FREQUENCY_DEFAULT, BXIV.SERIAL_PORT_NAME_1, BXIV.SERIAL_PORT_BAUD_RATE_57600,
                    screen.Ip, BXIV.SCREEN_PORT, Utility.pathScreenStatus + screen.ScreenStatusFile);
                isSendBusy = false;
            }
        }

        /// <summary>
        /// Setup screen parameters
        /// </summary>
        /// <param name="screenId"></param>
        /// <param name="isCOMMode">Default Enthenet Mode</param>
        public static void SetupScreenParameters(int screenId, bool isCOMMode = false)
        {
            if (isSendBusy == false)
            {
                isSendBusy = true;
                int mode = isCOMMode ? BXIV.SEND_MODE_COMM : BXIV.SEND_MODE_NET;
                int result = BXIV.SendScreenInfo(screenId, BXIV.SEND_MODE_NET, BXIV.SEND_CMD_PARAMETER, 0);
                isSendBusy = false;
            }
        }

        #endregion

        #region SEND_PROGRAMS

        public static void SendProgramToScreen(int screenId)
        {
            int result;
            VmsWebContext vms = new VmsWebContext();
            isSendBusy = false;
            if (isSendBusy == false)
            {
                isSendBusy = true;
                BXIV.InitDLLResource(Process.GetCurrentProcess().Handle);
                isSendBusy = false;
            }
            SCREEN screen = vms.SCREENS.Single(s => s.Id == screenId);
            int screenOrd = 1;
            AddScreenParameters(screenOrd, screen);
            // Screen not found

            int prgOrd = 0;
            PROGRAM program = screen.PROGRAMS.First();

            int mode = BXIV.SEND_MODE_NET;
            int playLength = program.PlayLength == null ? 0 : (int)program.PlayLength;
            int startYear = program.StartYear == null ? 65536 : (int)program.StartYear;
            int startMonth = program.StartMonth == null ? 1 : (int)program.StartMonth;
            int startDay = program.StartDay == null ? 1 : (int)program.StartDay;
            int endYear = program.EndYear == null ? 65536 : (int)program.EndYear;
            int endMonth = program.EndMonth == null ? 12 : (int)program.EndMonth;
            int endDay = program.EndDay == null ? 31 : (int)program.EndDay;
            int monPlay = (program.MonPlay == null || program.MonPlay == false) ? 0 : 1;
            int tuePlay = (program.TuePlay == null || program.TuePlay == false) ? 0 : 1;
            int wedPlay = (program.WedPlay == null || program.WedPlay == false) ? 0 : 1;
            int thuPlay = (program.ThuPlay == null || program.ThuPlay == false) ? 0 : 1;
            int friPlay = (program.FriPlay == null || program.FriPlay == false) ? 0 : 1;
            int satPlay = (program.SatPlay == null || program.SatPlay == false) ? 0 : 1;
            int sunPlay = (program.SunPlay == null || program.SunPlay == false) ? 0 : 1;
            int startHour = program.StartHour == null ? 0 : (int)program.StartHour;
            int startMinute = program.StartMinute == null ? 0 : (int)program.StartMinute;
            int endHour = program.EndHour == null ? 0 : (int)program.EndHour;
            int endMinute = program.EndMinute == null ? 0 : (int)program.EndMinute;

            // Add Screen Program.
            if (isSendBusy == false)
            {
                isSendBusy = true;
                result = BXIV.AddScreenProgram(screenOrd, 0, 0, 65535, 12, 3, endYear, endMonth, endDay,
                        monPlay, tuePlay, wedPlay, thuPlay, friPlay, satPlay, sunPlay,
                        startHour, startMinute, endHour, endMinute);
                isSendBusy = false;
            }
            // Get contents in each program
            CONTENT content = program.CONTENTS.First();
            int areaOrd = 0;

            foreach(CONTENT_TXT txt in content.CONTENT_TXT.ToList()) {
                string file = "";
                if (txt.TxtFileName.EndsWith(".bmp"))
                {
                    file = Utility.PathLibContentImg + txt.TxtFileName;
                }
                else
                {
                    file = Utility.PathScreenContentTxt + txt.TxtFileName;
                }
                int bold = (txt.Bold != null && txt.Bold == true) ? 1 : 0; 
                if (isSendBusy == false)
                {
                    isSendBusy = true;
                    result = BXIV.AddScreenProgramBmpTextArea(screenOrd, prgOrd, (int)txt.Txt_x, (int)txt.Txt_y, (int)txt.Txt_Width, (int)txt.Txt_Height);
                    isSendBusy = false;
                }
                if (isSendBusy == false)
                {
                    isSendBusy = true;
                    result = BXIV.AddScreenProgramAreaBmpTextFile(screenOrd, prgOrd, areaOrd, file, bold, txt.FontName, (int)txt.FontSize, bold, (int)txt.FontColor, (int)txt.DisplayMode, (int)txt.RunSpeed, (int)txt.ShowTime);
                    isSendBusy = false;
                }
                areaOrd++;
            }
            if (isSendBusy == false)
            {
                isSendBusy = true;
                result = BXIV.SendScreenInfo(screenOrd, mode, BXIV.SEND_CMD_SENDALLPROGRAM, 0);
                isSendBusy = false;
            }
            BXIV.FreeDLLResource();
            vms.Dispose();
        }

        /// <summary>
        /// Send Program to All Screen.
        /// </summary>
        /// <param name="isCOMMode">Default Enthenet Mode</param>
        public static void SendProgramsToAllScreens(bool isCOMMode = false)
        {
            VmsWebContext vms = new VmsWebContext();
            List<SCREEN> screens = vms.SCREENS.ToList();
            // Screen not found
            if (screens == null)
            {
                return;
            }

            int mode = isCOMMode ? BXIV.SEND_MODE_COMM : BXIV.SEND_MODE_NET;
            int areaOrd = 0;
            foreach (var screen in screens)
            {
                List<PROGRAM> programs = screen.PROGRAMS.ToList();
                if (programs == null)
                    continue;
                foreach (var program in programs)
                {
                    int playLength = program.PlayLength == null ? 0 : (int)program.PlayLength;
                    int startYear = program.StartYear == null ? 65536 : (int)program.StartYear;
                    int startMonth = program.StartMonth == null ? 1 : (int)program.StartMonth;
                    int startDay = program.StartDay == null ? 1 : (int)program.StartDay;
                    int endYear = program.EndYear == null ? 65536 : (int)program.EndYear;
                    int endMonth = program.EndMonth == null ? 12 : (int)program.EndMonth;
                    int endDay = program.EndDay == null ? 31 : (int)program.EndDay;
                    int monPlay = (program.MonPlay == null || program.MonPlay == false) ? 0 : 1;
                    int tuePlay = (program.TuePlay == null || program.TuePlay == false) ? 0 : 1;
                    int wedPlay = (program.WedPlay == null || program.WedPlay == false) ? 0 : 1;
                    int thuPlay = (program.ThuPlay == null || program.ThuPlay == false) ? 0 : 1;
                    int friPlay = (program.FriPlay == null || program.FriPlay == false) ? 0 : 1;
                    int satPlay = (program.SatPlay == null || program.SatPlay == false) ? 0 : 1;
                    int sunPlay = (program.SunPlay == null || program.SunPlay == false) ? 0 : 1;
                    int startHour = program.StartHour == null ? 0 : (int)program.StartHour;
                    int startMinute = program.StartMinute == null ? 0 : (int)program.StartMinute;
                    int endHour = program.EndHour == null ? 0 : (int)program.EndHour;
                    int endMinute = program.EndMinute == null ? 0 : (int)program.EndMinute;

                    // Add Screen Program
                    BXIV.AddScreenProgram(screen.Id, 0, playLength,
                        startYear, startMonth, startDay, endYear, endMonth, endDay,
                        monPlay, tuePlay, wedPlay, thuPlay, friPlay, satPlay, sunPlay,
                        startHour, startMinute, endHour, endMinute);
                    // Get contents in each program
                    List<CONTENT> contens = program.CONTENTS.ToList();
                    foreach (var content in contens)
                    {
                        // Get program Images in each content
                        List<CONTENT_IMG> imgs = content.CONTENT_IMG.ToList();
                        // Add content image to screen
                        foreach (var img in imgs)
                        {
                            // Add Image Area
                            BXIV.AddScreenProgramBmpTextArea(screen.Id, program.Id,
                                (int)img.Img_x, (int)img.Img_y, (int)img.Img_Width, (int)img.Img_Height);
                            // Add Image File
                            BXIV.AddScreenProgramAreaBmpTextFile(screen.Id, program.Id, areaOrd,
                                img.ImgFileName, 0, "", 0, 0, 0, (int)img.DisplayMode, (int)img.RunSpeed, (int)img.ShowTime);
                            areaOrd++;
                        }
                        // Get program Texts in each content.
                        List<CONTENT_TXT> txts = content.CONTENT_TXT.ToList();
                        // Add content text to screen
                        foreach (var txt in txts)
                        {
                            // Add text area.
                            BXIV.AddScreenProgramBmpTextArea(screen.Id, program.Id,
                                (int)txt.Txt_x, (int)txt.Txt_y, (int)txt.Txt_Width, (int)txt.Txt_Height);
                            // Add text area file
                            int bold = (txt.Bold == null || txt.Bold == false) ? 0 : 1;
                            BXIV.AddScreenProgramAreaBmpTextFile(screen.Id, program.Id, areaOrd,
                                txt.TxtFileName, (int)txt.ShowSingleLine, txt.FontName, (int)txt.FontSize,
                                bold, (int)txt.FontColor, (int)txt.DisplayMode, (int)txt.RunSpeed, (int)txt.ShowTime);
                            areaOrd++;
                        }
                    }
                    // Send Program to Screen.
                    if (!isSendBusy)
                    {
                        isSendBusy = true;
                        BXIV.SendScreenInfo(screen.Id, mode, BXIV.SEND_CMD_SENDALLPROGRAM, 0);
                        isSendBusy = false;
                    }
                }
            }
        }

        #endregion

        #region DELETE_SCREEN

        /// <summary>
        /// Delete Screen
        /// </summary>
        /// <param name="screenId"></param>
        /// <param name="isCOMMode">Default Enthenet Mode</param>
        /// <returns></returns>
        public static int DeleteScreen(int screenId, bool isCOMMode = false)
        {
            return BXIV.DeleteScreen(screenId);
        }

        /// <summary>
        /// Delete All Screen
        /// </summary>
        /// <param name="isCOMMode"></param>
        public static void DeleteAllScreen(bool isCOMMode = false)
        {
            VmsWebContext vms = new VmsWebContext();
            List<SCREEN> screens = vms.SCREENS.ToList();
            foreach (var screen in screens)
            {
                DeleteScreen(screen.Id, isCOMMode);
            }
        }

        #endregion

        #region GET_SCREEN_STATUS

        /// <summary>
        /// Get All Screen Status
        /// </summary>
        /// <param name="isCOMMode">Default Enthenet Mode</param>
        public static void GetAllScreensStatus(bool isCOMMode = false)
        {
            if (isSendBusy == false)
            {
                isSendBusy = true;
                BXIV.InitDLLResource(Process.GetCurrentProcess().Handle);
                isSendBusy = false;
            }
            VmsWebContext vms = new VmsWebContext();
            int mode = isCOMMode ? BXIV.SEND_MODE_COMM : BXIV.SEND_MODE_NET;
            List<SCREEN> screens = vms.SCREENS.ToList();
            if (screens == null)
                return;
            int screenOrd = 0;
            foreach (var screen in screens)
            {
                screenOrd++;
                AddScreenParameters(screenOrd, screen);
                int error = BXIV.RETURN_NOERROR;
                if (isSendBusy == false)
                {
                    isSendBusy = true;
                    error = BXIV.GetScreenStatus(screenOrd, mode);  // Auto update into screen status file .ini
                    isSendBusy = false;
                }
                string file = Utility.pathScreenStatus + screen.ScreenStatusFile;
                string section = "" + screen.Id;

                SCREEN_LOG screenLog = new SCREEN_LOG();
                SCREEN_STATUS screenStatus = screen.ScreenStatus;
                if (screenStatus == null)
                {
                    screenStatus = new SCREEN_STATUS();
                }
                screenLog.SCREEN = screen;
                // No error
                if (error == BXIV.RETURN_NOERROR)
                {
                    string currentTime = IniFile.Read(section, "RTC datetime", file);
                    string onoff = IniFile.Read(section, "On/Off", file);
                    int on_off = "Power on".Equals(onoff) ? 1 : 0;
                    string brightnessLevel = IniFile.Read(section, "Current brightness level", file);
                    string brightnessAdjustMode = IniFile.Read(section, "Brightness adjust mode", file);
                    string progid = IniFile.Read(section, "Current program", file);
                    int prg_id = int.Parse(progid.Replace("P", ""));

                    // Insert into SCREEN_LOG
                    screenLog.CurrentTime = currentTime;
                    screenLog.OnOff = on_off;
                    screenLog.CurrentProgram_Id = prg_id;
                    screenLog.Connection = 1;
                    screenLog.BrightnessAdjustMode = brightnessAdjustMode;
                    screenLog.BrightnessLevel = brightnessLevel;
                    screen.SCREEN_LOGS.Add(screenLog);

                    // Update last screen status into SCREEN_STATUS
                    screenStatus.CurrentTime = currentTime;
                    screenStatus.OnOff = on_off;
                    screenStatus.CurrentProgram_Id = prg_id;
                    screenStatus.Connection = 1;
                    screenStatus.BrightnessAdjustMode = brightnessAdjustMode;
                    screenStatus.BrightnessLevel = brightnessLevel;
                    vms.Entry(screen).State = EntityState.Modified;

                    // Update database
                    vms.SaveChanges();
                }
                // Comunication Error - Disconnect.
                else if ((0x01 <= error && error <= 0x08) || error == 0xFE)
                {
                    screenLog.Connection = 0;
                    screenStatus.Connection = 0;

                    screen.SCREEN_LOGS.Add(screenLog);
                    vms.Entry(screen).State = EntityState.Modified;

                    vms.SaveChanges();
                }
            } // end of for each.
            BXIV.FreeDLLResource();
        
        }

        #endregion

        #region BRIGHTNESS_SCREEN

        /// <summary>
        /// Send value of brightness to screen.
        /// </summary>
        /// <param name="screenId"></param>
        /// <param name="isCOMMode">Default enthernet mode</param>
        public static void SendScreenAdjustLight(int screenId, bool isCOMMode = false)
        {
            VmsWebContext vms = new VmsWebContext();
            SCREEN_BRIGHTNESS screenBrightness = vms.SCREENS.Single(s => s.Id == screenId).ScreenBrightness;
            if (screenBrightness == null)
            {
                return;
            }
            // Set the brigjtness of the screen.
            BXIV.SetScreenAjustLight(screenId, screenBrightness.nAdjustType, screenBrightness.nHandleLight,
                (int)screenBrightness.nHour1, (int)screenBrightness.nMinute1, (int)screenBrightness.nLight1,
                (int)screenBrightness.nHour2, (int)screenBrightness.nMinute2, (int)screenBrightness.nLight2,
                (int)screenBrightness.nHour3, (int)screenBrightness.nMinute3, (int)screenBrightness.nLight3,
                (int)screenBrightness.nHour4, (int)screenBrightness.nMinute4, (int)screenBrightness.nLight4);
            // Send value to screen.
            int mode = (isCOMMode) ? BXIV.SEND_MODE_COMM : BXIV.SEND_MODE_NET;
            if (!isSendBusy)
            {
                isSendBusy = true;
                BXIV.SendScreenInfo(screenId, mode, BXIV.SEND_CMD_ADJUSTLIGHT, 0);
                isSendBusy = false;
            }
        }

        /// <summary>
        /// Send value of brightness to all screen.
        /// </summary>
        /// <param name="isCOMMode">Default enthernet mode.</param>
        public static void SendAllScreensAdjustLight(bool isCOMMode = false)
        {
            VmsWebContext vms = new VmsWebContext();
            List<SCREEN> screens = vms.SCREENS.ToList();
            int mode = (isCOMMode) ? BXIV.SEND_MODE_COMM : BXIV.SEND_MODE_NET;
            foreach (var screen in screens)
            {
                SCREEN_BRIGHTNESS screenBrightness = screen.ScreenBrightness;
                if (screenBrightness == null)
                {
                    continue;
                }
                // Set the brigjtness of the screen.
                BXIV.SetScreenAjustLight(screen.Id, screenBrightness.nAdjustType, screenBrightness.nHandleLight,
                    (int)screenBrightness.nHour1, (int)screenBrightness.nMinute1, (int)screenBrightness.nLight1,
                    (int)screenBrightness.nHour2, (int)screenBrightness.nMinute2, (int)screenBrightness.nLight2,
                    (int)screenBrightness.nHour3, (int)screenBrightness.nMinute3, (int)screenBrightness.nLight3,
                    (int)screenBrightness.nHour4, (int)screenBrightness.nMinute4, (int)screenBrightness.nLight4);
                // Send value to screen.    
                if (!isSendBusy)
                {
                    isSendBusy = true;
                    BXIV.SendScreenInfo(screen.Id, mode, BXIV.SEND_CMD_ADJUSTLIGHT, 0);
                    isSendBusy = false;
                }
            }
        }

        #endregion
    }
}